home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / prgtools / programm.ing / ams__l~1.zoo / src / screen.cc < prev    next >
Encoding:
C/C++ Source or Header  |  1993-09-15  |  11.6 KB  |  541 lines

  1. //////////////////////////////////////////////////////////////////////////////
  2. //
  3. //  This file is part of the Atari Machine Specific Library,
  4. //  and is Copyright 1992 by Warwick W. Allison.
  5. //
  6. //  You are free to copy and modify these sources, provided you acknowledge
  7. //  the origin by retaining this notice, and adhere to the conditions
  8. //  described in the file COPYING.
  9. //
  10. //////////////////////////////////////////////////////////////////////////////
  11.  
  12. #include "Screen.h"
  13. #include "Resolution.h"
  14. #include "ca_pack.h"
  15. #include "ca_unpac.h"
  16. #include <stdio.h>
  17. #include <osbind.h>
  18. #include <alloc.h>
  19. #include <builtin.h>
  20. #include <dirent.h>
  21. #include <fnameext.h>
  22.  
  23. // TERMINATION code:
  24.  
  25. // used to ensure MyDisplayRestorer is linked in if possibly necessary
  26. #define EnsureRestoration MyDisplayRestorerPtr=&MyDisplayRestorer
  27.  
  28.  
  29. class DisplayRestorer
  30. {
  31. public:
  32.     DisplayRestorer() {
  33.         InitialPhysbase=(char*)Physbase();
  34.         InitialLogbase=(char*)Logbase();
  35.         for (int c=0; c<16; c++) InitialPalette[c]=Setcolor(c,-1);
  36.     }
  37.     ~DisplayRestorer() {
  38.         for (int c=0; c<16; c++) Setcolor(c,InitialPalette[c]);
  39.         Setscreen(InitialLogbase,InitialPhysbase,-1);
  40.     }
  41.  
  42. private:
  43.     char* InitialPhysbase;
  44.     char* InitialLogbase;
  45.     int InitialPalette[16];
  46. };
  47.  
  48. static DisplayRestorer MyDisplayRestorer;
  49. static DisplayRestorer* MyDisplayRestorerPtr;
  50.  
  51.  
  52.  
  53. static char *Page(char *adr)
  54. {
  55.     unsigned long a=(unsigned long)adr;
  56.     return (char *)((a+0xfe) & 0xffffff00);
  57. }
  58.  
  59. static char* AllocScreenRAM(long size)
  60. {
  61.     long ret=Mxalloc(size,0); // Ask for ST RAM
  62.  
  63.     // Did GEMDOS understand that call?  If not, use Malloc instead.
  64.     // (ie. assume it is an old ST without the notion of FastRAM)
  65.     if (ret==-32)
  66.         ret=Malloc(size);
  67.  
  68.     return (char*)ret;
  69. }
  70.  
  71. static void FreeScreenRAM(char* adr)
  72. {
  73.     Mfree(adr);
  74. }
  75.  
  76. Screen::Screen(const char* filename) :
  77.     location(0),
  78.     AllocArea(0),
  79.     Palette(0)
  80. {
  81.     EnsureRestoration;
  82.     if (!Load(filename)) {
  83.         FreeScreenRAM(AllocArea);
  84.         delete Palette;
  85.         location=0;
  86.         AllocArea=0;
  87.     }
  88. }
  89.  
  90. Screen::Screen(const Screen& Same) :
  91.     Res(Same.Res),
  92.     AllocSize(Res.BytesPerLine()*Res.Height()+0x100),
  93.     AllocArea(AllocScreenRAM(AllocSize)),
  94.     location(Page(AllocArea)),
  95.     Palette(new short[Res.NumberOfColours()])
  96. {
  97.     EnsureRestoration;
  98.     memcpy(location,Same.location,Res.BytesPerLine()*Res.Height());
  99.     memcpy(Palette,Same.Palette,sizeof(Palette[0])*Res.NumberOfColours());
  100. }
  101.  
  102. Screen::Screen(Resolution res) :
  103.     Res(res),
  104.     AllocSize(Res.BytesPerLine()*Res.Height()+0x100),
  105.     AllocArea(AllocScreenRAM(AllocSize)),
  106.     location(Page(AllocArea)),
  107.     Palette(new short[Res.NumberOfColours()])
  108. {
  109.     EnsureRestoration;
  110. }
  111.  
  112. Screen::Screen(short LinesAbove, short LinesBelow) :
  113.     Res(),
  114.     AllocSize(Res.BytesPerLine()*(Res.Height()+LinesAbove+LinesBelow)+0x100),
  115.     AllocArea(AllocScreenRAM(AllocSize)),
  116.     location(Page(AllocArea)),
  117.     Palette(new short[Res.NumberOfColours()])
  118. {
  119.     EnsureRestoration;
  120. }
  121.  
  122. Screen::Screen() :
  123.     Res(),
  124.     AllocSize(Res.BytesPerLine()*Res.Height()+0x100),
  125.     AllocArea(AllocScreenRAM(AllocSize)),
  126.     location(Page(AllocArea)),
  127.     Palette(new short[Res.NumberOfColours()])
  128. {
  129.     EnsureRestoration;
  130. }
  131.  
  132. Screen::Screen(long *At) :
  133.     Res()
  134. {
  135.     EnsureRestoration;
  136.  
  137.     AllocSize=0;
  138.     AllocArea=0;
  139.     if (At) {
  140.         location=(char*)At;
  141.     } else {
  142.         location=(char*)Physbase();
  143.     }
  144.     Palette=new short[Res.NumberOfColours()];
  145.     for (int i=0; i<Res.NumberOfColours(); i++) {
  146.         Palette[i]=Setcolor(i,-1);
  147.     }
  148. }
  149.  
  150. Screen::Screen(Resolution res, short LinesAbove, short LinesBelow) :
  151.     Res()
  152. {
  153.     EnsureRestoration;
  154.  
  155.     short BPL=res.BytesPerLine();
  156.     int BaseSize=BPL*res.Height()+0x100;
  157.  
  158.     AllocSize=BaseSize+(LinesAbove+LinesBelow)*BPL;
  159.     AllocArea=AllocScreenRAM(AllocSize),
  160.     location=Page(AllocArea+BPL*LinesAbove);
  161.     Palette=new short[res.NumberOfColours()];
  162.     Res=res;
  163. }
  164.  
  165. Screen::~Screen()
  166. {
  167.     if (AllocArea) FreeScreenRAM(AllocArea);
  168.     delete Palette;
  169. }
  170.  
  171.  
  172. void Screen::Clear()
  173. {
  174. /* Clear visible region? */
  175.     int i=Res.BytesPerLine()*Res.Height()/sizeof(long);
  176.     long * data=(long*) location;
  177.  
  178. /* ...or clear whole area?
  179.     int i=AllocSize/sizeof(long);
  180.     long *data=(long *)AllocArea;
  181. */
  182.  
  183.     while (i--) data[i]=0;
  184. }
  185.  
  186. #define CHECK(x) {if ((x)<=0) {fclose(file); return 0;}}
  187.  
  188. int Screen::LoadDegasPalette(const char *filename)
  189. {
  190.     FILE *file;
  191.     short res;
  192.  
  193.     file=fopen(filename,"rb");
  194.     if (!file) return 0;
  195.  
  196.     CHECK(fread(&res,sizeof(res),1,file));
  197.     Resolution NewRes(res);
  198.     CHECK(fread(Palette,sizeof(short),Res.NumberOfColours(),file));
  199.  
  200.     fclose(file);
  201.  
  202.     return 1;
  203. }
  204.  
  205. int Screen::LoadDegas(const char *filename)
  206. {
  207.     FILE *file;
  208.     short res;
  209.     short junk;
  210.  
  211.     file=fopen(filename,"rb");
  212.     if (!file) return 0;
  213.  
  214.     CHECK(fread(&res,sizeof(res),1,file));
  215.     Resolution NewRes(res);
  216.  
  217.     if (!Palette || NewRes.NumberOfColours()!=Res.NumberOfColours()) {
  218.         if (Palette) delete Palette;
  219.         Palette=new short[NewRes.NumberOfColours()];
  220.     }
  221.  
  222.     Res=NewRes;
  223.  
  224.     CHECK(fread(Palette,sizeof(short),Res.NumberOfColours(),file));
  225.     for (int ignore=16-Res.NumberOfColours(); ignore>0; ignore--)
  226.         CHECK(fread(&junk,sizeof(short),1,file));
  227.  
  228.     if (!location || AllocSize < Res.BytesPerLine()*Res.Height()+0x100) {
  229.         if (AllocArea) FreeScreenRAM(AllocArea);
  230.         AllocSize=Res.BytesPerLine()*Res.Height()+0x100;
  231.         AllocArea=AllocScreenRAM(AllocSize);
  232.         location=Page(AllocArea);
  233.     }
  234.  
  235.     CHECK(fread(location,1,Res.BytesPerLine()*Res.Height(),file));
  236.  
  237.     fclose(file);
  238.  
  239.     return 1;
  240. }
  241.  
  242. int Screen::SaveDegas(const char *filename)
  243. {
  244.     FILE *file;
  245.     short res;
  246.  
  247.     file=fopen(filename,"wb");
  248.     if (!file) return 0;
  249.  
  250.     res=Res.OldMode();
  251.     CHECK(fwrite(&res,sizeof(short),1,file));
  252.     CHECK(fwrite(Palette,sizeof(short),Res.NumberOfColours(),file));
  253.     if (Res.NumberOfColours() < 16) {
  254.         short junk=0;
  255.         for (int ignore=16-Res.NumberOfColours(); ignore; ignore--)
  256.             CHECK(fwrite(&junk,sizeof(short),1,file));
  257.     }
  258.  
  259.     CHECK(fwrite(location,1,Res.BytesPerLine()*Res.Height(),file));
  260.     fclose(file);
  261.  
  262.     return 1;
  263. }
  264.  
  265.  
  266. PaletteChange::PaletteChange() :
  267.     ncols(16),
  268.     col(new short[ncols])
  269. {
  270.     for (int i=0; i<ncols; i++) {
  271.         col[i]=Setcolor(i,-1);
  272.     }
  273. }
  274.  
  275. PaletteChange::~PaletteChange()
  276. {
  277.     Setpalette(col);
  278.  
  279.     delete col;
  280. }
  281.  
  282. /////////////////////////////////////////////////
  283. //                                             //
  284. //  CrackArt I/O as per GFA basic code:        //
  285. //                                             //
  286. //    CRACK ART 'CA_PACK'                      //
  287. //                                             //
  288. //    Kompressionsroutine für CA?-Bilder       //
  289. //                                             //
  290. //    © Detlef Röttger & Jan Borchers 1989-91  //
  291. //                                             //
  292. /////////////////////////////////////////////////
  293.  
  294. int Screen::LoadCrackArtPalette(const char *Filename)
  295. {
  296.     FILE* fp=fopen(Filename,"rb");
  297.  
  298.     if (!fp) return 0;
  299.  
  300.     char Magic[2];
  301.     fread(Magic,sizeof(char),2,fp);
  302.     if (Magic[0]!='C' || Magic[1]!='A') {
  303.         fclose(fp);
  304.         return 0;
  305.     }
  306.  
  307.     short res;
  308.     fread(&res,sizeof(short),1,fp);
  309.     Resolution NewRes(res&255);
  310.  
  311.     if (NewRes.NumberOfColours()!=Res.NumberOfColours()) {
  312.         return 0;
  313.     }
  314.  
  315.     // NB. CrackArt file format is WRONG for CA3 - it doesn't save a palette
  316.     //     this is very wrong - especially on the TT.  So we can't load one.
  317.     if (Res==STHigh) {
  318.         Palette[0]=0x777;
  319.         Palette[1]=0x000;
  320.     } else {
  321.         fread(Palette,sizeof(short),Res.NumberOfColours(),fp);
  322.     }
  323.  
  324.     fclose(fp);
  325.  
  326.     return 1;
  327. }
  328.  
  329. int Screen::LoadCrackArt(const char *Filename)
  330. {
  331.     FILE* fp=fopen(Filename,"rb");
  332.  
  333.     if (!fp) return 0;
  334.  
  335.     char Magic[2];
  336.     fread(Magic,sizeof(char),2,fp);
  337.     if (Magic[0]!='C' || Magic[1]!='A') {
  338.         fclose(fp);
  339.         return 0;
  340.     }
  341.  
  342.     short res;
  343.     fread(&res,sizeof(short),1,fp);
  344.     Resolution NewRes(res&255);
  345.  
  346.     if (!Palette || NewRes.NumberOfColours()!=Res.NumberOfColours()) {
  347.         if (Palette) delete Palette;
  348.         Palette=new short[NewRes.NumberOfColours()];
  349.     }
  350.  
  351.     // NB. CrackArt file format is WRONG for CA3 - it doesn't save a palette
  352.     //     this is very wrong - especially on the TT.  We could load one,
  353.     //     expecting CrackArt to correct the problem, if they ever support
  354.     //     mono rez, but then we couldn't load them!  Perhaps we could add a
  355.     //     hack to set a bit in the reserved byte after Rez, but it's not
  356.     //     our format!  Now the question is, do we make CrackArt's mistake
  357.     //     again and not support a palette in TTHigh?  No.
  358.     if (NewRes==STHigh) {
  359.         Palette[0]=0x777;
  360.         Palette[1]=0x000;
  361.     } else {
  362.         fread(Palette,sizeof(short),NewRes.NumberOfColours(),fp);
  363.     }
  364.  
  365.     Res=NewRes;
  366.  
  367.     if (!location || AllocSize < Res.BytesPerLine()*Res.Height()+0x100) {
  368.         if (AllocArea) FreeScreenRAM(AllocArea);
  369.         AllocSize=Res.BytesPerLine()*Res.Height()+0x100;
  370.         AllocArea=AllocScreenRAM(AllocSize);
  371.         location=Page(AllocArea);
  372.     }
  373.  
  374.     LoadCrackArtData((unsigned char*)location,Res.BytesPerLine()*Res.Height(),fp);
  375.  
  376.     fclose(fp);
  377.  
  378.     return 1;
  379. }
  380.  
  381.  
  382. int Screen::SaveCrackArt(const char *Filename, int Compression=3)
  383. {
  384.     FILE* fp=fopen(Filename,"wb");
  385.  
  386.     if (!fp) return 0;
  387.  
  388.     fwrite("CA",sizeof(char),2,fp);
  389.  
  390.     short res=256+Res.OldMode();
  391.     fwrite(&res,sizeof(short),1,fp);
  392.  
  393.     // NB. CrackArt file format is WRONG for CA3 - it doesn't save a palette
  394.     //     this is very wrong - especially on the TT.  So we don't save one.
  395.     if (Res!=STHigh) fwrite(Palette,sizeof(short),Res.NumberOfColours(),fp);
  396.  
  397.     SaveCrackArtData((unsigned char*)location,Res.BytesPerLine()*Res.Height(),fp,Compression);
  398.  
  399.     fclose(fp);
  400.  
  401.     return 1;
  402. }
  403.  
  404. int DegasExtension(char *ext)
  405. {
  406.     return (ext[0]=='p' && ext[1]=='i' && ext[2]>='1' && ext[2]<='8');
  407. }
  408.  
  409. int CrackArtExtension(char *ext)
  410. {
  411.     return (ext[0]=='c' && ext[1]=='a' && ext[2]>='1' && ext[2]<='8');
  412. }
  413.  
  414. enum FileType { Unknown,Degas,CrackArt };
  415.  
  416. FileType FindAppropriateFile(const char* filename, char* appropriate)
  417. {
  418.     char ext[strlen(filename)+1];
  419.     extension(ext,filename);
  420.  
  421.     if (!ext[0]) {
  422.         FileType Type=Unknown;
  423.  
  424.         char dir[strlen(filename)+1];
  425.         char name[strlen(filename)+1];
  426.  
  427.         basename(name,filename);
  428.         noextension(name,name);
  429.  
  430.         strlwr(dir);
  431.         strlwr(name);
  432.  
  433.         directory(dir,filename);
  434.         DIR* D=opendir(dir);
  435.  
  436.         dirent* entry;
  437.  
  438.         int found=0;
  439.         int result;
  440.  
  441.         while (!found && (entry=readdir(D))) {
  442.             char base[strlen(entry->d_name)+1];
  443.             char ext[strlen(entry->d_name)+1];
  444.  
  445.             noextension(base,entry->d_name);
  446.             extension(ext,entry->d_name);
  447.  
  448.             strlwr(base);
  449.             strlwr(ext);
  450.  
  451.             if (0==strcmp(base,name)) {
  452.                 found=1; // Yes... maybe.
  453.                 if (DegasExtension(ext)) {
  454.                     strcpy(appropriate,dir);
  455.                     strcat(appropriate,entry->d_name);
  456.                     Type=Degas;
  457.                 } else if (CrackArtExtension(ext)) {
  458.                     strcpy(appropriate,dir);
  459.                     strcat(appropriate,entry->d_name);
  460.                     Type=CrackArt;
  461.                 } else {
  462.                     found=0; // Oh, no it wasn't.
  463.                 }
  464.             }
  465.         }
  466.  
  467.         closedir(D);
  468.  
  469.         return Type;
  470.     } else {
  471.         strlwr(ext);
  472.         if (DegasExtension(ext)) {
  473.             strcpy(appropriate,filename);
  474.             return Degas;
  475.         } else if (CrackArtExtension(ext)) {
  476.             strcpy(appropriate,filename);
  477.             return CrackArt;
  478.         }
  479.     }
  480.     return Unknown;
  481. }
  482.  
  483. int Screen::Load(const char* filename)
  484. {
  485.     char RealName[strlen(filename)+10];
  486.     switch (FindAppropriateFile(filename,RealName)) {
  487.      case Degas:
  488.         return LoadDegas(RealName);
  489.     break; case CrackArt:
  490.         return LoadCrackArt(RealName);
  491.     break; default:
  492.         return 0;
  493.     }
  494. }
  495.  
  496. int Screen::LoadPalette(const char* filename)
  497. {
  498.     char RealName[strlen(filename)+10];
  499.     switch (FindAppropriateFile(filename,RealName)) {
  500.      case Degas:
  501.         return LoadDegasPalette(RealName);
  502.     break; case CrackArt:
  503.         return LoadCrackArtPalette(RealName);
  504.     break; default:
  505.         return 0;
  506.     }
  507. }
  508.  
  509. int Screen::Save(const char* filename)
  510. {
  511.     char ext[strlen(filename)+1];
  512.     extension(ext,filename);
  513.     strlwr(ext);
  514.  
  515.     if (DegasExtension(ext)) {
  516.         return SaveDegas(filename);
  517.     } else if (CrackArtExtension(ext)) {
  518.         return SaveCrackArt(filename);
  519.     } else {
  520.         return 0;
  521.     }
  522. }
  523.  
  524.  
  525. void Screen::operator= (Screen& orig)
  526. {
  527.     if (orig.Res==Res) {
  528.         int i=Res.BytesPerLine()*Res.Height()/sizeof(long);
  529.         long* to=(long*) location;
  530.         long* from=(long*) orig.location;
  531.  
  532.         while (i--) to[i]=from[i];
  533.     }
  534. }
  535.  
  536. // This is needed because my copy of GNU.OLB leaves DIRENTSIZ undefined!
  537. int DIRENTSIZ(int x)
  538. {
  539.     return __DIRENTSIZ(x);
  540. }
  541.